#include "DatePackerDialog.h"
#include "cocos-ext.h"
USING_NS_CC_EXT;

static const u_int8_t sun_month_days[12]={
        31,28,31,30,31,30,
        31,31,30,31,30,31
};
#define is_leap_year(year) 	(!((year)%400) || (!((year)%4) && ((year)%100)))
#define days_of_sun_month(sunDate) ((is_leap_year((sunDate).y) && ((sunDate).m==2)) ? 29 : sun_month_days[(sunDate).m-1])
/*********************| DatePackerStep class |*********************/

class DatePackerStep : public CCNode, public CCEditBoxDelegate
{
public:
					DatePackerStep();
public:
	bool 				init(const int defualt,
					     const int min, const int max);
	void				editBoxReturn(CCEditBox *editBox);
	void				setMinMax(const int min, const int max);
private:
	void				actionCB(CCObject* obj);
	void				checkBtnEnable();
	void				updateData();
public:
	int				data;
	CCMenu*				menu;
	CCEditBox*			_editBox;
	CCObject*			sender;
	SEL_CallFunc			_selector;
private:
	enum {
		ADD_ACTION = 0,
		SUB_ACTION = 1
	};
	int 				_lmin;
	int 				_lmax;
};

DatePackerStep::DatePackerStep()
{
	data = _lmin = _lmax = 0;
	_editBox = NULL;
	menu = NULL;
	sender = NULL;
	_selector = NULL;
}

bool DatePackerStep::init(const int defualt, const int min, const int max)
{
	bool bRet = false;
	do {
		data = defualt;
		_lmin = 0;
		_lmax = 0;
		CCScale9Sprite* tmp9Sp = CCScale9Sprite::create("dialog/date_pbg.png");
		CC_BREAK_IF(!tmp9Sp);
		_editBox = CCEditBox::create(CCSizeMake(80, 50), tmp9Sp);
		CC_BREAK_IF(!_editBox);
		_editBox->setPosition(CCPointZero);
		_editBox->setFont("DroidSansFallbackFull", 18);
		_editBox->setFontColor(ccBLACK);
		if (max > 31) {
			_editBox->setMaxLength(4);
		} else {
			_editBox->setMaxLength(2);
		}
		_editBox->setReturnType(kKeyboardReturnTypeDone);
		_editBox->setInputMode(kEditBoxInputModeNumeric);
		_editBox->setDelegate(this);
		this->addChild(_editBox);
		CCMenuItemImage* addBtn = CCMenuItemImage::create("dialog/add_n.png",
		                                                  "dialog/add_s.png",
		                                                  this, menu_selector(DatePackerStep::actionCB));
		CC_BREAK_IF(!addBtn);
		addBtn->setAnchorPoint(ccp(0.5, 0));
		addBtn->setPosition(ccp(0, 25));
		CCMenuItemImage* subBtn = CCMenuItemImage::create("dialog/sub_n.png",
		                                                  "dialog/sub_s.png",
		                                                  this, menu_selector(DatePackerStep::actionCB));
		CC_BREAK_IF(!subBtn);
		subBtn->setAnchorPoint(ccp(0.5, 1));
		subBtn->setPosition(ccp(0, -25));
		addBtn->setTag(ADD_ACTION);
		subBtn->setTag(SUB_ACTION);
		menu = CCMenu::create(addBtn, subBtn, NULL);
		CC_BREAK_IF(!menu);
		menu->setPosition(CCPointZero);
		this->addChild(menu);

		this->setContentSize(CCSizeMake(80, 104));
		updateData();
		setMinMax(min, max);

		bRet = true;
	}while(0);
	return bRet;
}

void DatePackerStep::editBoxReturn(CCEditBox* editBox)
{
	int tmp = atoi(editBox->getText());
	if (tmp < _lmin) {
		data = _lmin;
	} else if (tmp > _lmax) {
		data = _lmax;
	} else {
		data = tmp;
	}
	updateData();
	checkBtnEnable();
}

void DatePackerStep::actionCB(CCObject* obj)
{
	const int ac_tag = ((CCNode*)obj)->getTag();
	bool doAction = false;
	if (DatePackerStep::ADD_ACTION == ac_tag) {
		/* 执行加法运算 */
		if (data < _lmax) {
			++data;
			updateData();
			doAction = true;
		}
	} else {
		if (data > _lmin) {
			--data;
			updateData();
			doAction = true;
		}
	}
	if (doAction && sender && _selector) {
		(sender->*_selector)();
	}
	checkBtnEnable();
}

void DatePackerStep::checkBtnEnable()
{
	CCMenuItemImage* addBtn = (CCMenuItemImage*)menu->getChildByTag(ADD_ACTION);
	CCMenuItemImage* subBtn = (CCMenuItemImage*)menu->getChildByTag(SUB_ACTION);
	if (data >= _lmax && addBtn->isEnabled()) {
		addBtn->setEnabled(false);
		addBtn->setColor(ccGRAY);
	} else if (data < _lmax && !addBtn->isEnabled()) {
		addBtn->setEnabled(true);
		addBtn->setColor(ccWHITE);
	} else if (data <= _lmin && subBtn->isEnabled()) {
		subBtn->setEnabled(false);
		subBtn->setColor(ccGRAY);
	} else if (data > _lmin && !subBtn->isEnabled()) {
		subBtn->setEnabled(true);
		subBtn->setColor(ccWHITE);
	}
}

void DatePackerStep::updateData()
{
	char buf[5] = {0};
	sprintf(buf, "%d", data);
	_editBox->setText(buf);
}

void DatePackerStep::setMinMax(const int min, const int max)
{
	if (min < max) {
		if (max != _lmax) {
			_lmax = max;
			if (data > _lmax) {
				data = _lmax;
				updateData();
			}
		}
		if (min != _lmin) {
			_lmin = min;
			if (data < _lmin) {
				data = _lmin;
				updateData();
			}
		}
		checkBtnEnable();
	}
}

/*********************| DatePackerDialog func |*********************/
int DatePackerDialog::convertCTimeToDate(time_t time, DatePackerDialog::date_t* out)
{
	if (out) {
		struct tm* t = gmtime(&time);
		if (t) {
			out->y = 1900 + t->tm_year;
			out->m = t->tm_mon + 1;
			out->d = t->tm_mday;
			return 0;
		}
	}
	return -1;
}

DatePackerDialog::DatePackerDialog()
{
	memset(_packer, 0, sizeof(_packer));
}

DatePackerDialog::~DatePackerDialog()
{
	int i;
	for (i = 0; i < DATE_PACKER_CNT; ++i) {
		CC_SAFE_RELEASE(_packer[i]);
	}
}

bool DatePackerDialog::init()
{
	bool bRet = false;
	do {
		CC_BREAK_IF(!YesNoPortrol::init("请选择日期",
						CCSizeMake(330, 250)));
		date_t now;
		convertCTimeToDate(time(0), &now);

		_packer[DATE_PACKER_YEAR] = new DatePackerStep();
		CC_BREAK_IF(!_packer[DATE_PACKER_YEAR]->init(now.y - 1, 1900, now.y));
		_packer[DATE_PACKER_YEAR]->sender = this;
		_packer[DATE_PACKER_YEAR]->_selector = callfunc_selector(DatePackerDialog::updateDayFromYear);

		_packer[DATE_PACKER_MON] = new DatePackerStep();
		CC_BREAK_IF(!_packer[DATE_PACKER_MON]->init(now.m, 1, 12));
		_packer[DATE_PACKER_MON]->sender = this;
		_packer[DATE_PACKER_MON]->_selector = callfunc_selector(DatePackerDialog::updateDayFromMon);

		_packer[DATE_PACKER_DAY] = new DatePackerStep();
		CC_BREAK_IF(!_packer[DATE_PACKER_DAY]->init(now.d , 1, 30));
		updateDayFromMon();

		int i;
		for (i = 0; i < DATE_PACKER_CNT; ++i) {
			_packer[i]->setAnchorPoint(ccp(0, 0));
			_packer[i]->setPosition(ccp(_bg->boundingBox().getMinX() + i * 90 + 75,
						    _bg->boundingBox().getMidY() + 15));
			this->addChild(_packer[i]);
			this->addACanTouchLayer(_packer[i]->menu);
			this->addACanTouchLayer(_packer[i]->_editBox);
		}
		bRet = true;
	}while(0);
	return bRet;
}

const size_t DatePackerDialog::getRetCode()
{
	_date.y = _packer[DATE_PACKER_YEAR]->data;
	_date.m = _packer[DATE_PACKER_MON]->data;
	_date.d = _packer[DATE_PACKER_DAY]->data;
	date_t now;
	convertCTimeToDate(time(0), &now);
	size_t ret;
	size_t tmp1 = _date.y * 10000 + _date.m * 100 + _date.d;
	size_t tmp2 = now.y * 10000 + now.m * 100 + now.d;
	if (tmp1 < tmp2) {
		memcpy(&ret, &_date, sizeof(size_t));
	} else {
		memcpy(&ret, &now, sizeof(size_t));
	}
	return ret;
}

void DatePackerDialog::updateDayFromYear()
{
	/* 只有可能是在2月的时候，年份会引起mday的变化 */
	if (2 == _packer[DATE_PACKER_MON]->data) {
		date_t tmp = {_packer[DATE_PACKER_YEAR]->data, 2, 1 };
		_packer[DATE_PACKER_DAY]->setMinMax(1, days_of_sun_month(tmp));
	}
}

void DatePackerDialog::updateDayFromMon()
{
	/* 月份变化却会引起很大的变化 */
	date_t tmp = {
		_packer[DATE_PACKER_YEAR]->data,
		_packer[DATE_PACKER_MON]->data,
		1
	};
	_packer[DATE_PACKER_DAY]->setMinMax(1, days_of_sun_month(tmp));
}
